﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using NPMonitor.Helpers;

namespace NPMonitor.DataModel
{
    /// <summary>
    /// Contains all the information that is known about a job before execution time.
    /// </summary>
    [Serializable]
    [Table("BackgroundWorkerJobs")]
    public class JobData
    {
        /// <summary>
        /// Gets the auto generated job id.
        /// </summary>
        /// <value>The auto generated job id.</value>
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }

        /// <summary>
        /// Gets or sets the user defined unique id of the job.  This is seperate from the rowId and can be used when deleting/re-creating jobs.
        /// </summary>
        /// <value>
        /// The unique id.
        /// </value>
        [Required]
        public Guid UniqueId { get; set; }

        /// <summary>
        /// Gets or sets unique id of job assembly file
        /// </summary>
        //[Required]
        //public Guid FileUniqueId { get; set; }

        /// <summary>
        /// Gets the job data.
        /// </summary>
        /// <value>The job data.</value>
        public string Data { get; set; }

        /// <summary>
        /// Gets or sets the job meta data.
        /// </summary>
        /// <value>The job meta data.</value>
        public string MetaData { get; set; }
        /// <summary>
        /// Gets or sets the error message (if any) associated with this job.
        /// </summary>
        /// <value>ErrorMessage will be set if the job did not return a success result.</value>
        public string LastErrorMessage { get; set; }
        /// <summary>
        /// Gets the name of the BackgroundWorkerInstance Service instance that has picked up this job.
        /// </summary>
        public string Instance { get; set; }

        /// <summary>
        /// Gets the DateTime when this job was created.
        /// </summary>
        [Required]
        public DateTime CreatedDate { get; set; }

        /// <summary>
        /// Gets the DateTime when this job started executing.
        /// </summary>
        /// <value>
        /// A null value means the job has not been started.  
        /// This value will be non-null if a job as started executing at least once.
        /// Value is reset when job starts to execute.
        /// </value>
        [Column("LastExecutionStartDateTime")]
        public DateTime? LastStartTime { get; set; }

        /// <summary>
        /// Gets the DateTime when the job execution finished.
        /// </summary>
        /// <value>
        /// A null value means the job has not once finished execution. 
        /// This value will be non-null if a job as finished executing at least once.
        /// A non-null value does not indicate success, simply that the job has finished executing at least once.
        /// Value is reset when job starts to execute.
        /// </value>
        [Column("LastExecutionEndDateTime")]
        public DateTime? LastEndTime { get; set; }

        [Column("NextExecutionStartDateTime")]
        public DateTime? NextStartTime { get; set; }

        /// <summary>
        /// Gets or sets the time that this job is allowed to run, before being forcefully terminated.
        /// </summary>
        /// <value>
        /// A null value means that the job will never forcefully be terminated (except perhaps on service shutdown).
        /// </value>
        public TimeSpan? AbsoluteTimeout { get; set; }

        /// <summary>
        /// Gets the current status of this job.
        /// </summary>
        /// <value>
        /// This value changes depending on where in the execution lifecycle the job is currently.
        /// </value>
        [NotMapped]
        public JobStatus Status
        {
            get
            {
                JobStatus tStatus = (JobStatus)StatusId;

                if (tStatus == JobStatus.Executing)
                {
                    if (string.Compare(this.GetMachineStatusByMachineName(MachineName).Trim(), Connectivities.Unconnected.ToString().Trim()) == 0)
                    {
                        return JobStatus.Unknown;
                    }
                }
                return tStatus;

            }
            set { StatusId = (int)value; }
        }

        public int StatusId { get; set; }

        /// <summary>
        /// Gets or sets which queue will be used to execute this job.
        /// </summary>
        [Required]
        public int QueueId { get; set; }

        /// <summary>
        /// Gets or sets an optional schedule.  If not set, the job is assumbed to be a once off job and will be executed as soon as possible.
        /// </summary>
        /// <value>
        /// The schedule that this job will be executed on.
        /// </value>
        public string Schedule { get; set; }

        public string ScheduleType { get; set; }

        public string ScheduleRunningType
        {
            get
            {
                if (string.IsNullOrWhiteSpace(Schedule))
                {
                    return "Run Once";
                }
                else
                {
                    return "Schedule";
                }
            }
        }

        /// <summary>
        /// Gets or sets the optional application.
        /// </summary>
        /// <value>
        /// The application name - used as a way to distinguish jobs in the same jobstore.
        /// </value>
        public string Application { get; set; }

        /// <summary>
        /// Gets or sets the optional group.
        /// </summary>
        /// <value>
        /// The group name - used as a way to distinguish jobs in the same jobstore and application.
        /// </value>
        public string Group { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether history records are created or not.
        /// </summary>
        /// <value>
        ///   If you do not wish a <see cref="JobExecutionHistory"/> record to be created, set this value to <c>true</c>.
        /// </value>
        [Required]
        public bool SuppressHistory { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the job is permanently deleted after a successfull (<see cref="JobStatus.Done"/>) execution.
        /// </summary>
        /// <value>
        ///   Set to <c>true</c> if you do not want the job to be in the database if it completed successfully.
        /// </value>
        [Required]
        public bool DeleteWhenDone { get; set; }

        /// <summary>
        /// Gets or sets the optional descriptive name of the job.
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public string Name { get; set; }

        /// <summary>
        /// Get or set the Machine name
        /// </summary>
        public string MachineName { get; set; }

        /// <summary>
        /// Gets or sets the optional description.
        /// </summary>
        /// <value>
        /// The description.
        /// </value>
        public string Description { get; set; }

        public int? TaskId { get; set; }

        public int JobId { get; set; }

        public bool? Retry { get; set; }

        public bool? AutoRetry { get; set; }

        public int? RetryTimes { get; set; }

        public int? MaxRetry { get; set; }

        [NotMapped]
        public string ErrorCode { get; set; }
        
        /// <summary>
        /// TaskType:Job,Workflow
        /// </summary>
        public string TaskType { get; set; }

        [NotMapped]
        public TaskType JobTaskType
        {
            get
            {
                return Utils.GetEnum<TaskType>(this.TaskType, NPMonitor.TaskType.Job);
            }

            set
            {
                this.TaskType = value.ToString();
            }
        }

        public string CreatedBy { get; set; }

        ISchedule _JobSchedule = null;

        [NotMapped]
        public ISchedule JobSchedule
        {
            get
            {
                if (_JobSchedule == null && !string.IsNullOrEmpty(this.ScheduleType))
                {
                    return (ISchedule)Utils.DeserializeObject(this.Schedule, Type.GetType(this.ScheduleType));
                }

                return null;
            }
        }

        [Required]
        public bool IsDelete { get; set; }

        private string jobWorkflowName = null;

        [NotMapped]
        public string JobWorkflowName
        {
            get
            {
                if (jobWorkflowName == null)
                {
                    if (TaskId != null)
                    {
                        jobWorkflowName = this.GetNameByTaskId(TaskId.Value, TaskType);
                    }
                    else
                    {
                        jobWorkflowName = "";
                    }
                }

                return jobWorkflowName;
            }
        }

        private string poolName = null;

        [NotMapped]
        public string PoolName
        {
            get
            {
                if (poolName == null)
                {
                    poolName = this.GetPoolNameByMachineName(MachineName);
                }
                return poolName;
            }
        }

        [NotMapped]
        public CalendarSchedule ScheduleDetails
        {
            get
            {
                if (null != Schedule)
                {
                    return (CalendarSchedule)Utils.DeserializeObject(Schedule, Type.GetType(this.ScheduleType));
                }

                return null;
            }
        }

    }
}
